﻿using System;
using System.Collections.Generic;
using System.Linq;
using HtmlAgilityPack;
using System.Net;
using System.Collections;
using System.Web;
using System.Drawing;

/// <summary>
/// IMDb API
/// </summary>
public class IMDb
{
    /// <summary>
    /// Contains all options for the movie page
    /// </summary>
    public class MoviePage
    {
        /// <summary>
        /// Contains the Html code of the selected url
        /// </summary>
        public string HtmlCode;
        private string _url;
        private readonly HtmlDocument _htmlMainPage = new HtmlDocument();
        private string HtmlDownloader
        {
            get
            {
                using (WebClient client = new WebClient())
                {
                    return client.DownloadString(_url);
                }
            }
        }
        /// <summary>
        /// The Url from the IMDb Movie Page
        /// </summary>
        /// <example>
        /// http://www.imdb.com/title/tt0460681
        /// </example>
        public string Url
        {
            get
            {
                return _url;
            }
            set
            {
                _url = value.TrimEnd('/');
                HtmlCode = HtmlDownloader;
                _htmlMainPage.LoadHtml(HtmlCode);
            }
        }
        /// <summary>
        /// Gets the cover image from the movie page
        /// </summary>
        public Image CoverImage
        {
            get
            {
                //*[@id="img_primary"]/a
                //*[@id="img_primary"]/div/a/img                
                try
                {
                    string url = _htmlMainPage.DocumentNode.SelectSingleNode("//*[@id='img_primary']/div/a/img").GetAttributeValue("src", "");
                    WebRequest client = WebRequest.Create(url);
                    using (var response = client.GetResponse())
                    using (var stream = response.GetResponseStream())
                    {
                        return Image.FromStream(stream);
                    }
                }
                catch
                {
                    return null;
                }
            }
        }
        /// <summary>
        /// Gets the name of the movie
        /// </summary>
        public string Name
        {
            get
            {
                //*[@id="overview-top"]/h1/text()
                //*[@id="overview-top"]/h1/span[1]
                return HttpUtility.HtmlDecode(_htmlMainPage.DocumentNode.SelectSingleNode("//*[@id='overview-top']/h1/span[1]").InnerText.Replace("&#9668;&nbsp;", "").Trim());
            }
        }
        /// <summary>
        /// Gets the release year from the movie
        /// </summary>
        public string Year
        {
            get
            {
                return HttpUtility.HtmlDecode(_htmlMainPage.DocumentNode.SelectSingleNode("//*[@id='overview-top']/h1/span").InnerText.Replace("(", "").Replace(")", "").Trim());
            }
        }
        /// <summary>
        /// Gets the genre(s) from the movie
        /// </summary>
        public string Genre
        {
            get
            {
                //*[@id="overview-top"]/div[2]/a[1]
                //*[@id="overview-top"]/div[2]
                string genre = HttpUtility.HtmlDecode(_htmlMainPage.DocumentNode.SelectSingleNode("//*[@id='overview-top']/div[2]").InnerText);
                genre = genre.Remove(0, genre.IndexOf("-") + 1);
                return genre.Remove(genre.IndexOf("-") - 1, genre.Count() - genre.IndexOf("-") - 1).Trim();
            }
        }
        /// <summary>
        /// Gets the IMDb rating for the movie
        /// </summary>
        public string Rating
        {
            get
            {
                //*[@id="overview-top"]/div[3]/div[1]
                return HttpUtility.HtmlDecode(_htmlMainPage.DocumentNode.SelectSingleNode("//*[@id='overview-top']/div[3]/div[1]").InnerText.Replace("\n", ""));
            }
        }
        /// <summary>
        /// Gets the movie description
        /// </summary>
        public string Description
        {
            get
            {
                //*[@id="overview-top"]/p[2]
                return HttpUtility.HtmlDecode(_htmlMainPage.DocumentNode.SelectSingleNode("//p[@itemprop='description']").InnerText.Replace("\n", ""));
            }
        }
        /// <summary>
        /// Gets the creator of the movie if available
        /// </summary>
        public string Creator
        {
            get
            {
                //*[@id="overview-top"]/div[4]/a
                string creator = HttpUtility.HtmlDecode(_htmlMainPage.DocumentNode.SelectSingleNode("//*[@id='overview-top']/div[4]").InnerText);
                if (creator.Contains("Creator:"))
                {
                    return creator.Replace("Creator:", "").Replace("\n", "").TrimStart();
                }
                else
                {
                    return null;
                }
            }
        }
        /// <summary>
        /// Gets the stars that are on the movie page
        /// </summary>
        public string Stars
        {
            get
            {
                //*[@id="overview-top"]/div[6]/h4
                return HttpUtility.HtmlDecode(_htmlMainPage.DocumentNode.SelectSingleNode("//*[@id='overview-top']/div[6]").InnerText.Replace("Stars:", "").Replace("\n", "")).Replace("|See full cast and crew", "");
            }
        }
        /// <summary>
        /// Gets the director(s) of the movie
        /// </summary>
        public string Director
        {
            get
            {
                //*[@id="overview-top"]/div[4]/a
                //*[@id="overview-top"]/div[4]
                string Director = HttpUtility.HtmlDecode(_htmlMainPage.DocumentNode.SelectSingleNode("//*[@id='overview-top']/div[4]").InnerText);
                if (Director.Contains("Directors:") || Director.Contains("Director:"))
                {
                    Director = Director.Replace("Directors:", "").Replace("Director:", "").Replace("\n", "").Trim();
                    if (Director.EndsWith("»"))
                    {
                        Director = Director.Remove(Director.LastIndexOf(','), Director.Count() - Director.LastIndexOf(','));
                    }
                    return Director;
                }
                else
                {
                    return null;
                }
            }
        }
        /// <summary>
        /// Gets the movie writer(s)
        /// </summary>
        public string Writers
        {
            get
            {
                //*[@id="overview-top"]/div[5]
                string Writers = HttpUtility.HtmlDecode(_htmlMainPage.DocumentNode.SelectSingleNode("//*[@id='overview-top']/div[5]").InnerText);
                if (Writers.Contains("Writer:") || Writers.Contains("Writers:"))
                {
                    Writers = Writers.Replace("Writer:", "").Replace("Writers:", "").Replace("\n", "").Trim();
                    if (Writers.EndsWith("»"))
                    {
                        Writers = Writers.Remove(Writers.LastIndexOf(','), Writers.Count() - Writers.LastIndexOf(','));
                    }
                    return Writers;
                }
                else
                {
                    return null;
                }
            }
        }
        /// <summary>
        /// Gets the trailer link if available
        /// </summary>
        public string TrailerLink
        {
            get
            {
                try
                {
                    //*[@id="overview-bottom"]/a
                    string url = HttpUtility.HtmlDecode(_htmlMainPage.DocumentNode.SelectSingleNode("//*[@id='overview-bottom']/a").OuterHtml);
                    url = url.Remove(0, url.IndexOf("href=") + 6);
                    return "http://www.imdb.com" + url.Remove(url.IndexOf('"'), url.Count() - url.IndexOf('"'));
                }
                catch
                {
                    return null;
                }
            }
        }
    }
    /// <summary>
    /// Contains all options for the episodes page of a series
    /// </summary>
    public class EpisodesPage
    {
        /// <summary>
        /// Contains the Html code of the episodes page
        /// </summary>
        public string HtmlCode;
        private string _url;
        private readonly HtmlDocument _htmlEpisodesPage = new HtmlDocument();
        private string HtmlDownloader
        {
            get
            {
                using (WebClient client = new WebClient())
                {
                    return client.DownloadString(_url);
                }
            }
        }
        /// <summary>
        /// The url of the episodes page
        /// </summary>
        /// <example>
        /// http://www.imdb.com/title/tt0460681/episodes
        /// </example>
        public string Url
        {
            get
            {
                return _url;
            }
            set
            {
                _url = value.TrimEnd('/');
                HtmlCode = HtmlDownloader;
                _htmlEpisodesPage.LoadHtml(HtmlCode);
            }
        }
        /// <summary>
        /// Returns the currently selected season
        /// </summary>
        public int GetSelectedSeasonNumber
        {
            get
            {
                return Convert.ToInt32(_htmlEpisodesPage.DocumentNode.SelectSingleNode("//h3[@id='episode_top']").InnerText.Replace("&nbsp;", " ").Replace("Season ", ""));
            }
        }
        /// <summary>
        /// Sets the season to be used for the current series
        /// </summary>
        /// <param name="Season"></param>
        /// <returns></returns>
        public int SetSeason(int Season)
        {
            try
            {
                if (_url.Contains("?season="))
                {
                    _url = _url.Remove(_url.IndexOf("?season="), _url.Count() - _url.IndexOf("?season="));
                }
                Url = String.Format("{0}?season={1}", _url, Season);
                return 0;
            }
            catch
            {
                System.Windows.Forms.MessageBox.Show("Season doesn't exists!");
                return 0;
            }
        }
        /// <summary>
        /// Get the amount of episodes of the current selected episode
        /// </summary>
        public int GetAmountOfEpisodes
        {
            get
            {
                try
                {
                    HtmlNodeCollection oneven = _htmlEpisodesPage.DocumentNode.SelectNodes("//div[@class='list_item odd']");
                    HtmlNodeCollection even = _htmlEpisodesPage.DocumentNode.SelectNodes("//div[@class='list_item even']");
                    if (oneven != null)
                    {
                        if ((even != null))
                        {
                            return oneven.Count + even.Count;
                        }
                        else
                        {
                            return oneven.Count;
                        }
                    }
                    else
                    {
                        return even.Count;
                    }
                }
                catch
                {
                    System.Windows.Forms.MessageBox.Show("Season doesn't exists!");
                    return 0;
                }
            }
        }
        /// <summary>
        /// Gets the names of the episodes from the selected season
        /// </summary>
        /// <param name="AmountOfEpisodes"></param>
        /// <returns></returns>
        public ArrayList EpisodesNames(int AmountOfEpisodes)
        {
            //*[@id="episodes_content"]/div[2]/div[2]/div[1]/div[2]/strong/a
            ArrayList episodes = new ArrayList();
            if (AmountOfEpisodes == 1)
            {
                episodes.Add(_htmlEpisodesPage.DocumentNode.SelectSingleNode("//*[@id='episodes_content']/div[2]/div[1]/div/div[2]/strong/a").InnerText);
            }
            else
            {
                for (int i = 0; i < AmountOfEpisodes; i++)
                {
                    episodes.Add(_htmlEpisodesPage.DocumentNode.SelectSingleNode(String.Format("//*[@id='episodes_content']/div[2]/div[2]/div[{0}]/div[2]/strong/a", (i + 1))).InnerText);
                }
            }
            return episodes;
        }
        /// <summary>
        /// Returns the name of the selected series, can contains some weird chars. MoviePage.Name is better.
        /// </summary>
        public string NameSeries
        {
            get
            {
                return HttpUtility.HtmlDecode(_htmlEpisodesPage.DocumentNode.SelectSingleNode("//*[@id='main']/div/div[1]/h3").InnerText.Replace("&#9668;&nbsp;", "").Trim());
            }
        }
        /// <summary>
        /// returns the release dates of the episodes of the currently selected season
        /// </summary>
        /// <param name="AmountOfEpisodes"></param>
        /// <returns></returns>
        public ArrayList EpisodesReleaseDates(int AmountOfEpisodes)
        {
            //*[@id="episodes_content"]/div[2]/div[2]/div[1]/div[2]/div[1]
            //*[@id="episodes_content"]/div[2]/div[2]/div[2]/div[2]/div[1]
            ArrayList releases = new ArrayList();
            if (AmountOfEpisodes == 1)
            {
                releases.Add(_htmlEpisodesPage.DocumentNode.SelectSingleNode("//*[@id='episodes_content']/div[2]/div[1]/div/div[2]/div[1]").InnerText.Trim());
            }
            else
            {
                for (int i = 0; i < AmountOfEpisodes; i++)
                {
                    releases.Add(_htmlEpisodesPage.DocumentNode.SelectSingleNode(String.Format("//*[@id='episodes_content']/div[2]/div[2]/div[{0}]/div[2]/div[1]", (i + 1))).InnerText.Trim());
                }
            }
            return releases;
        }
        /// <summary>
        /// Returns the descriptions of the episodes from the currently selected season
        /// </summary>
        /// <param name="AmountOfEpisodes"></param>
        /// <returns></returns>
        public ArrayList EpisodesDescriptions(int AmountOfEpisodes)
        {
            //*[@id="episodes_content"]/div[2]/div[2]/div[2]/div[2]/div[2]
            //*[@id="episodes_content"]/div[2]/div[2]/div[3]/div[2]/div[2]
            ArrayList descriptions = new ArrayList();
            if (AmountOfEpisodes == 1)
            {
                descriptions.Add(_htmlEpisodesPage.DocumentNode.SelectSingleNode("//*[@id='episodes_content']/div[2]/div[1]/div/div[2]/div[2]").InnerText);
            }
            else
            {
                for (int i = 0; i < AmountOfEpisodes; i++)
                {
                    descriptions.Add(_htmlEpisodesPage.DocumentNode.SelectSingleNode(String.Format("//*[@id='episodes_content']/div[2]/div[2]/div[{0}]/div[2]/div[2]", (i + 1))).InnerText);
                }
            }
            return descriptions;
        }
        /// <summary>
        /// returns all the episodes covers from the currently selected season
        /// </summary>
        /// <param name="AmountOfEpisodes"></param>
        /// <returns></returns>
        public System.Windows.Forms.ImageList EpisodesCovers(int AmountOfEpisodes)
        {
            System.Windows.Forms.ImageList covers = new System.Windows.Forms.ImageList();
            covers.ImageSize = new Size(120, 180);
            if (AmountOfEpisodes == 1)
            {
                //*[@id="episodes_content"]/div[2]/div[2]/div[1]/div[1]/a/div/img
                //*[@id="episodes_content"]/div[2]/div[2]/div[2]/div[1]/a/div/img
                string url = _htmlEpisodesPage.DocumentNode.SelectSingleNode("//*[@id='episodes_content']/div[2]/div[2]/div[1]/div[1]/a/div/img").OuterHtml;
                url = url.Remove(0, url.IndexOf("src=") + 5);
                url = url.Remove(url.IndexOf(">") - 1, url.Count() - url.IndexOf(">") + 1);
                WebRequest client = WebRequest.Create(url);
                using (var response = client.GetResponse())
                using (var stream = response.GetResponseStream())
                {
                    covers.Images.Add(Image.FromStream(stream));
                }
            }
            else
            {
                for (int i = 0; i < AmountOfEpisodes; i++)
                {
                    string url = _htmlEpisodesPage.DocumentNode.SelectSingleNode(String.Format("//*[@id='episodes_content']/div[2]/div[2]/div[{0}]/div[1]/a/div/img", (i + 1))).OuterHtml;
                    url = url.Remove(0, url.IndexOf("src=") + 5);
                    url = url.Remove(url.IndexOf(">") - 1, url.Count() - url.IndexOf(">") + 1);
                    WebRequest client = WebRequest.Create(url);
                    using (var response = client.GetResponse())
                    using (var stream = response.GetResponseStream())
                    {
                        covers.Images.Add(Image.FromStream(stream));
                    }
                }
            }
            return covers;
        }
    }
}
